package com.yf.custom.aop;

import com.yf.custom.annotation.LoginAction;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.YamlMapFactoryBean;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * @ClassName YfLogAspect
 * @Description TODO
 * @Author yf
 * @Date 2018/10/15 17:02
 * @Version 1.0
 */
@Aspect
@Component
@Order(-99) // 控制多个Aspect的执行顺序，越小越先执行
public class YfLogAspect {
    private static final Logger LOGGER= LoggerFactory.getLogger(YfLogAspect.class);


    @Pointcut("execution(* com.yf.custom..*.*(..))")
    private void pointcut(){ }


    @Before("pointcut() && @annotation(YfLog)")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        // 接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 打印日志
        LOGGER.info("before : url=" + request.getRequestURL().toString());
    }


    /**
     *  ProceedingJoinPoint is only supported for around advice
     *  环绕通知=前置+目标方法执行+后置通知，proceed方法就是用于启动目标方法执行的。
     环绕通知 ProceedingJoinPoint 执行proceed方法的作用是让目标方法执行，这也是环绕通知和前置、后置通知方法的一个最大区别。
     Proceedingjoinpoint 继承了 JoinPoint 。是在JoinPoint的基础上暴露出 proceed 这个方法。proceed很重要，这个是aop代理链执行的方法
     */
    @Around(value = "pointcut() && @annotation(yfLog)")
    public Object before(ProceedingJoinPoint  point, YfLog yfLog){
        Class clazz = point.getTarget().getClass();
        String method =point.getSignature().getName();
        //入口参数
        StringBuilder logSB=new StringBuilder();
        Object[] args = point.getArgs();
        int i = args.length;
        for (Object arg : args) {
            logSB.append(arg.toString() + ",");
        }
        LOGGER.info("around start: class=" + clazz + ",method=" + method +",params="+logSB.toString());
        try {
            //执行程序
            Object object=point.proceed();
            LOGGER.info("around over: result="+object.toString());
            return object;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            return throwable.getMessage();
        }
    }
}
